#include "console.h"
#include "thread.h"
#include "general.h"
#include "interrupt.h"
#include "ansi.h"

/* auto execute function type definition */
typedef void (*auto_init_t) (void);

/* main thread */
static mx_thread_t main_thread;
static mx_align_cpu mx_uint8_t main_stack[MX_DEFAULT_STACK_SIZE];
extern mx_int32_t main (void);
static mx_int32_t main_thread_entry (mx_void_pt param)
{
    /* execute application init automatically */
    symbol_execute_auto(MX_SYMBOL_CLUSTER_APPINIT, auto_init_t);
    /* goto main */
    return main();
}

/* idle thread */
static mx_thread_t idle_thread;
static mx_align_cpu mx_uint8_t idle_stack[MX_DEFAULT_STACK_SIZE];
extern mx_int32_t idle (void);
static mx_int32_t idle_thread_entry (mx_void_pt param)
{
    /* don't exit the idle function if it implement */
    idle();
    /* maybe unreachable */
    while (mx_true);
    /* unreachable */
    return -1;
}

mx_inline static void mxlogo ()
{
    consoleline(ANSI_CSI_SGR(0) ENDL "Welcom to MatrixOS (Latest CT: %s %s)" ENDL, __DATE__, __TIME__);
    consoleline("  ███╗   ███╗ █████╗ ████████╗██████╗ ██╗██╗  ██╗");
    consoleline("  ████╗ ████║██╔══██╗╚══██╔══╝██╔══██╗██║╚██╗██╔╝");
    consoleline("  ██╔████╔██║███████║   ██║   ██████╔╝██║ ╚███╔╝ ");
    consoleline("  ██║╚██╔╝██║██╔══██║   ██║   ██╔══██╗██║ ██╔██╗ ");
    consoleline("  ██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║██║██╔╝ ██╗");
    consoleline("  ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═╝╚═╝  ╚═╝ " ENDL);
    consoleline("System initialization succeeded.");
}

void mxboot (void)
{
    /* disable global interrupt */
    mx_interrupt_disable();

    /* initialize symbol export */
    symbol_execute_auto(MX_SYMBOL_CLUSTER_BOARDINIT, auto_init_t);

    /* console initialization */
    console_init(MX_DEFAULT_CONSOLE_DEVNAME, MX_DEFAULT_CONSOLE_BUFSIZE);

    /* system logo */
    mxlogo();

    /* main thread initialize */
    mx_thread_mount(&main_thread, "main", MX_DEFAULT_PRIORITY, MX_DEFAULT_TICK,
                    main_stack, len(mx_uint8_t, main_stack), main_thread_entry, mx_null);
    mx_thread_start(&main_thread);

    /* idle thread initialize */
    mx_thread_mount(&idle_thread, "idle", MX_PRIORITY_MIN, MX_DEFAULT_TICK,
                    idle_stack, len(mx_uint8_t, idle_stack), idle_thread_entry, mx_null);
    mx_thread_start(&idle_thread);

    /* starting thread state machine,
       the first thread's interrupt must be enabled when constructing stack in `stack.c`,
       so here needn't enable interrupt */
    mx_thread_schedule();

    /* ATTENTION never be here */
    return;
}
